<template>
  <div style="width: 100%">
    <div style="border: 1px solid #ccc;">
      <!-- 工具栏 -->
      <toolbar
        style="border-bottom: 1px solid #ccc"
        :editor="editor"
        :defaultConfig="toolbarConfig"
        :mode="mode"
      />
      <!-- 编辑器 -->
      <editor
        :style="{height: height + 'px',overflowY: 'hidden'}"
        :defaultConfig="editorConfig"
        v-model="html"
        :mode="mode"
        @onCreated="onCreated"
        @onChange="onChange"
      />
      <!--      @customPaste="onCustomPaste"-->
      <div class="text-length-wrapper">
        <span class="text-length"
              :style="{color:textLength>maxlength?'red':'#ccc'}">{{ `${textLength} / ${maxlength}` }}</span>
      </div>
    </div>
  </div>
</template>

<script>
import { VITE_APP_UPLOAD_URL} from '@/api/upload'
// import {Boot, SlateNode} from '@wangeditor/editor'
// import {Editor, Toolbar} from '@wangeditor/editor-for-vue'
import {getToken} from "@/utils/auth";
import {MessagePlugin as Message} from 'tdesign-vue';

function getLeftLengthOfMaxLength(editor) {
  const {customMaxLength, onMaxLength} = editor.getConfig()
  // 未设置 maxLength ，则返回 number 最大值
  // if (typeof maxLength !== 'number' || maxLength <= 0) return Infinity

  const editorText = editor.getText().replace(/\r|\n|(\r\n)/g, '') // 去掉换行
  // const curLength = editorText.length
  const curLength = editorText.replace(/\s+/g, '').length
  const leftLength = customMaxLength - curLength
  if (leftLength <= 0) {
    // 触发 maxLength 限制，不再继续插入文字
    if (onMaxLength) onMaxLength(editor)
  }

  return leftLength
}

function withMaxLength(editor) {
  const {insertText, insertNode, insertFragment, dangerouslyInsertHtml} = editor
  const newEditor = editor
  // 处理 text
  newEditor.insertText = (text) => {
    const {customMaxLength} = newEditor.getConfig()
    if (!customMaxLength) {
      insertText(text)
      return
    }

    const leftLength = getLeftLengthOfMaxLength(newEditor)
    if (leftLength <= 0) {
      // 已经触发 maxLength ，不再输入文字
      return
    }
    if (leftLength < text.length) {
      // 剩余长度小于 text 长度，则截取 text
      insertText(text.slice(0, leftLength))
      return
    }

    insertText(text)
  }

  // 处理 node
  newEditor.insertNode = (node) => {
    const {customMaxLength} = newEditor.getConfig()
    if (!customMaxLength) {
      insertNode(node)
      return
    }

    const leftLength = getLeftLengthOfMaxLength(newEditor)
    if (leftLength <= 0) {
      // 已经触发 maxLength ，不再插入
      return
    }

    const text = SlateNode.string(node)
    if (leftLength < text.length) {
      // 剩余长度，不够 node text 长度，不再插入
      return
    }

    insertNode(node)
  }

  // 处理 fragment
  newEditor.insertFragment = (fragment) => {
    const {customMaxLength} = newEditor.getConfig()
    if (!customMaxLength) {
      // 无 maxLength
      insertFragment(fragment)
      return
    }

    // 只有一个 node 时，使用 insertFragment ，防止换行
    if (fragment.length === 1) {
      const node = fragment[0]
      const leftLength = getLeftLengthOfMaxLength(newEditor)
      const text = SlateNode.string(node)

      if (leftLength < text.length) {
        // 已经触发 maxLength ，不再插入
        return
      }

      insertFragment(fragment)
      return
    }
    // 有 maxLength ，则分别插入 node
    fragment.forEach(n => {
      newEditor.insertNode(n) // 【注意】这里必须使用 `e.insertNode` ，而不是 insertNode
    })
  }

  newEditor.dangerouslyInsertHtml = (html, isRecursive = false) => {
    if (!html) return

    const {customMaxLength} = newEditor.getConfig()
    if (!customMaxLength) {
      // 无 maxLength
      dangerouslyInsertHtml(html, isRecursive)
      return
    }
    const leftLength = getLeftLengthOfMaxLength(newEditor)
    if (leftLength <= 0) {
      // 已经触发 maxLength ，不再输入文字
      return
    }

    // ------------- 把 html 转换为 DOM nodes -------------
    const div = document.createElement('div')
    div.innerHTML = html
    const text = Array.from(div.childNodes).reduce((acc, node) => {
      const {nodeType, nodeName} = node
      if (!node) {
        return acc
      }
      // export enum NodeType {
      //   ELEMENT_NODE = 1,
      //     TEXT_NODE = 3,
      //     CDATA_SECTION_NODE = 4,
      //     PROCESSING_INSTRUCTION_NODE = 7,
      //     COMMENT_NODE = 8,
      //     DOCUMENT_NODE = 9,
      //     DOCUMENT_TYPE_NODE = 10,
      //     DOCUMENT_FRAGMENT_NODE = 11,
      // }
      // Text Node
      if (nodeType === 3) return acc + (node.textContent || '')

      // Element Node
      if (nodeType === 1) {
        const IGNORE_TAGS = new Set([
          'doctype',
          '!doctype',
          'meta',
          'script',
          'style',
          'link',
          'frame',
          'iframe',
          'title',
          'svg', // TODO 暂时忽略
        ])
        // 过滤掉忽略的 tag
        if (IGNORE_TAGS.has(nodeName.toLowerCase())) return acc
        return acc + (node.textContent || '')
      }
      return acc
    }, '')
    if (leftLength < text.length) {
      return
    }
    dangerouslyInsertHtml(html, isRecursive)
  }

  return newEditor // 返回 editor 实例
}

Boot.registerPlugin(withMaxLength)
export default {
  name: 'MyEditor',
  components: {Editor, Toolbar},
  props: {
    value: {
      type: String,
      default: ''
    },
    maxlength: {
      type: Number,
      default: 1000
    },
    height: {
      type: [String, Number],
      default: 300
    },
    jsonContent: {
      type: Array,
      default: () => [
        {
          type: 'paragraph',
          lineHeight: '1.5',
          children: [
            { text: '', fontFamily: '宋体', fontSize: '12pt' }
          ]
        },
      ]
    }
  },
  data() {
    return {
      editor: null,
      html: '<p style="line-height: 1.5;"><span style="font-size: 12pt; font-family: 宋体;"></span></p>',
      toolbarConfig: {
        // toolbarKeys: [ /* 显示哪些菜单，如何排序、分组 */ ],
        excludeKeys: ['fontSize', 'fontFamily', 'lineHeight'],
      },
      editorConfig: {
        placeholder: '请输入内容...',
        customMaxLength: this.maxlength,
        // maxLength: this.maxlength,
        // autoFocus: false,
        // 所有的菜单配置，都要在 MENU_CONF 属性下
        MENU_CONF: {
          // fontFamily: {
          //   // fontFamilyList: [
          //   //   // { name: '默认字体', value: '宋体' },
          //   //   { name: '宋体', value: '宋体' },
          //   // ],
          // },
          fontSize: {
            fontSizeList: [
              // 元素支持两种形式
              //   1. 字符串；
              //   2. { name: 'xxx', value: 'xxx' }
              // { name: '默认字号', value: '12pt' },
              {name: '初号', value: '44pt'},
              {name: '小初', value: '36pt'},
              {name: '一号', value: '26pt'},
              {name: '小一', value: '24pt'},
              {name: '二号', value: '22pt'},
              {name: '小二', value: '18pt'},
              {name: '三号', value: '16pt'},
              {name: '小三', value: '15pt'},
              {name: '四号', value: '14pt'},
              {name: '小四', value: '12pt'},
              // {name: '小四2', value: '16px'},
              {name: '五号', value: '10.5pt'},
              {name: '小五', value: '9pt'},
              {name: '六号', value: '7.5pt'},
              {name: '小六', value: '6.5pt'},
              {name: '八号', value: '5pt'},
            ]
          },
          uploadImage: {
            fieldName: 'file',
            headers: {
              Authorization: `Bearer ${getToken()}`,
            },
            // 单个文件的最大体积限制，默认为 2M
            maxFileSize: 30 * 1024 * 1024, // 10M
            server: VITE_APP_UPLOAD_URL,
            base64LimitSize: 30 * 1024 * 1024,
            // customInsert(res, insertFn) {
            //   //   "url": "xxx", // 图片 src ，必须
            //   //   "alt": "yyy", // 图片描述文字，非必须
            //   //   "href": "zzz" // 图片的链接，非必须
            //   if (res.code !== 200) {
            //     Message.error(`文件上传失败`);
            //   } else {
            //     const url = res.data.fullFilePath;
            //     insertFn(url, "", "")
            //   }
            // }
          }
        }
      },
      mode: 'default', // or 'simple'
      textLength: 0,
      msg: null
    }
  },
  // computed: {
  //   textLength() {
  //     const text = this.editor.getText()
  //     return text.length
  //   }
  // },
  watch: {
    value: {
      handler(val) {
        this.html = val;
      },
      deep: true,
      immediate: true
    }
  },
  mounted() {
    // 模拟 ajax 请求，异步渲染编辑器
    // setTimeout(() => {
    //   this.html = '<p>Ajax 异步设置内容 HTML</p>'
    // }, 1500)
  },
  beforeDestroy() {
    const {editor} = this
    if (editor == null) return
    editor.destroy() // 组件销毁时，及时销毁 editor ，重要！！！
  },
  methods: {
    onCreated(editor) {
      this.editor = Object.seal(editor) // 【注意】一定要用 Object.seal() 否则会报错
    },
    onChange(editor) {
      // 为空会默认赋值影响非空判断
      const html = this.html === "<p><br></p>" || this.html === '<p style="line-height: 1.5;"><br></p>' ? "" : this.html;
      const text = this.editor.getText().replace(/\r|\n|(\r\n)/g, '') // 去掉换行
      const inLine = text.replaceAll(/\s/g, '')
      this.textLength = inLine.length
      const doc = new DOMParser().parseFromString(html, 'text/html');
      const span = doc.getElementsByTagName("span")
      const spanList = Array.prototype.slice.call(span);
      spanList.forEach((val,index)=>{
        spanList[index].style.fontFamily = "宋体"
        spanList[index].style.fontSize = "12pt"
      })
      const p = doc.getElementsByTagName("p")
      const pList = Array.prototype.slice.call(p);
      pList.forEach((val,index)=>{
        pList[index].style.lineHeight = "1.5"
        // pList[index].setAttribute('style', 'lineHeight:1.5');
      })
      this.$emit("input", doc.body.innerHTML);
    },
    getTextLength() {
      return this.textLength
    },
    onCustomPaste(editor, event) {
      const html = event.clipboardData.getData('text/html') // 获取粘贴的 html
      const text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本


      // const template = document.createElement('template');
      // const parser = new DOMParser();
      // const doc = parser.parseFromString(this.html, 'text/xml');
      if (html) {
        // eslint-disable-next-line prefer-destructuring
        // 1.替换方案
        // let s =  html.match(/<!--StartFragment-->(.*?)<!--EndFragment-->/simg)[0]
        // s = s.replace(/[\n\r]/g,' ')
        // s = s.replaceAll(/font-size:(.*?);/simg, 'font-size:12pt;')
        // s = s.replaceAll(/font-family:(.*?);/simg, 'font-family: 宋体;')

        // 2.纯文本方案
        // const lines = text.split('\n')
        // let s = ''
        // lines.forEach(line => {
        //   line = line.replace('\r', '')
        //   const h = `<p style="line-height: 1.5;"><span style="font-size: 12pt; font-family: 宋体;">${line}</span></p>`
        //   s += h
        // })
        // const doc = new DOMParser().parseFromString(html, 'text/html');
        // const span = doc.getElementsByTagName("span")
        // const spanList = Array.prototype.slice.call(span);
        // spanList.forEach((val,index)=>{
        //   spanList[index].style.setProperty("font-size","12pt")
        //   // spanList[index].style.fontFamily = "宋体"
        //   // spanList[index].style.fontSize = "12pt !important"
        // })
        // const p = doc.getElementsByTagName("p")
        // const pList = Array.prototype.slice.call(p);
        // pList.forEach((val,index)=>{
        //   pList[index].style.lineHeight = "1.5"
        //   // pList[index].setAttribute('style', 'lineHeight:1.5');
        // })
        // editor.dangerouslyInsertHtml(doc.body.innerHTML)
        // editor.setHtml(doc.body.innerHTML)
        // editor.setHtml(doc.body.innerHTML)
        // 阻止默认的粘贴行为
        event.preventDefault()
        return false
      }
      // 使用默认粘贴行为
      return true
    },
    onMaxLength() {
      if (!this.msg) {
        this.msg = this.$message.warning('超出字数限制！')
      } else {
        this.$message.close(this.msg)
        this.msg = this.$message.warning('超出字数限制！')
      }
    }
  },
}
</script>

<!--<style src="@wangeditor/editor/dist/css/style.css"></style>-->
<style lang="less" scoped>
.text-length-wrapper {
  position: relative;
  height: 22px;

  .text-length {
    position: absolute;
    right: 10px;
  }
}
/deep/ .w-e-text-container{
  font-size: 12pt;
  font-family: 宋体;
  line-height: 1.5;
  p{
    margin: 0px;
  }
}
/deep/ .w-e-text-placeholder{
  top: 2px
}
</style>
